﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using System.Threading;
using System.Timers;

namespace VideoScreensaver 
{
    public enum MonitorState
    {
        MonitorStateOn = -1,
        MonitorStateOff = 2,
        MonitorStateStandBy = 1
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window 
    {
        [DllImport("user32.dll")]
        private static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);

        private System.Threading.Timer t;

        private bool preview;
        private bool shuffle;
        public bool blacken;
        private int video_playing = 0;
        public List<BlackWindow> black_windows;
        private Point? lastMousePosition = null;  // Workaround for "MouseMove always fires when maximized" bug.
        private double volume 
        {
            get { return FullScreenMedia.Volume; }
            set 
            {
                FullScreenMedia.Volume = Math.Max(Math.Min(value, 1), 0);
            }
        }

        public MainWindow(bool preview) 
        {
            InitializeComponent();
            this.preview = preview;
            this.shuffle = PreferenceManager.ReadShuffleSetting();
            this.blacken = PreferenceManager.ReadBlackenSetting();
            FullScreenMedia.Volume = PreferenceManager.ReadVolumeSetting();
            if (this.preview)
            {
                ShowError("When fullscreen, control volume with up/down arrows. Skip to next or previous video with the left/right arrows.");
            }
            else
            {
                if (this.blacken)
                {
                    black_windows = new List<BlackWindow>();
                    foreach (System.Windows.Forms.Screen screen in System.Windows.Forms.Screen.AllScreens)
                    {
                        if (screen != System.Windows.Forms.Screen.PrimaryScreen)
                        {
                            black_windows.Add(new BlackWindow(screen));
                        }
                    }
                }
            
                // set monitor off timer event
                uint monitor_off_timer_seconds = Power.GetMonitorOffTime();
                t = new System.Threading.Timer(MonitorOffEvent, null, monitor_off_timer_seconds * 1000, System.Threading.Timeout.Infinite);


            }
        }

        public void SendEnterKey()
        {
            if (Keyboard.PrimaryDevice != null)
            {
                if (Keyboard.PrimaryDevice.ActiveSource != null)
                {
                    var e = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Enter)
                    {
                        RoutedEvent = Keyboard.KeyDownEvent
                    };
                    InputManager.Current.ProcessInput(e);

                    // Note: Based on your requirements you may also need to fire events for:
                    // RoutedEvent = Keyboard.PreviewKeyDownEvent
                    // RoutedEvent = Keyboard.KeyUpEvent
                    // RoutedEvent = Keyboard.PreviewKeyUpEvent
                }
            }
        }

        public void MonitorOffEvent(object state)
        {
            Action a = SendEnterKey;
            Dispatcher.Invoke(a);
        }

        private void ScrKeyDown(object sender, KeyEventArgs e) 
        {
            switch (e.Key) 
            {
                case Key.Up:
                    volume += 0.1;
                    break;
                case Key.Down:
                    volume -= 0.1;
                    break;
                case Key.D0:
                    volume = 0;
                    break;
                case Key.Left:
                    PreviousVideo();
                    break;
                case Key.Right:
                    MediaEnded(null, null);
                    break;
                case Key.Enter:
                    SendMessage(0xFFFF, 0x112, 0xF170, (int)MonitorState.MonitorStateOff);
                    Thread.Sleep(2000);
                    EndFullScreensaver();
                    break;
                default:
                    EndFullScreensaver();
                    break;
            }
        }

        private void ScrMouseWheel(object sender, MouseWheelEventArgs e) 
        {
            volume += e.Delta / 1000.0;
        }

        private void ScrMouseMove(object sender, MouseEventArgs e) 
        {
            // Workaround for bug in WPF.
            Point mousePosition = e.GetPosition(this);
            if (lastMousePosition != null && mousePosition != lastMousePosition) 
            {
                EndFullScreensaver();
            }
            lastMousePosition = mousePosition;
        }

        private void ScrMouseDown(object sender, MouseButtonEventArgs e) 
        {
            EndFullScreensaver();
        }

        private void ScrSizeChange(object sender, SizeChangedEventArgs e) 
        {
            FullScreenMedia.Width = e.NewSize.Width;
            FullScreenMedia.Height = e.NewSize.Height;
        }

        // End the screensaver only if running in full screen. No-op in preview mode.
        private void EndFullScreensaver() 
        {
            if (!preview)
            {
                Close();
                if (blacken)
                {
                    foreach (BlackWindow b in black_windows)
                    {
                        b.Close();
                    }
                }
            }
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            List<String> videoPaths = PreferenceManager.ReadVideoSettings();
            if (videoPaths.Count == 0) 
            {
                ShowError("This screensaver needs to be configured before any video is displayed.");
            }
            else 
            {
                int v = 0;
                if (this.shuffle)
                {
                    v = new Random().Next(videoPaths.Count);
                }
                else
                {
                    v = this.video_playing;
                }
                FullScreenMedia.Source = new System.Uri(videoPaths[v]);

            }
        }

        private void ShowError(string errorMessage) 
        {
            ErrorText.Text = errorMessage;
            ErrorText.Visibility = System.Windows.Visibility.Visible;
            if (preview) 
            {
                ErrorText.FontSize = 12;
            }
        }

        private void PreviousVideo()
        {
            List<String> videoPaths = PreferenceManager.ReadVideoSettings();
            if (videoPaths.Count == 0)
            {
                ShowError("This screensaver needs to be configured before any video is displayed.");
            }
            else
            {
                if (this.shuffle)
                {
                    FullScreenMedia.Source = new System.Uri(videoPaths[new Random().Next(videoPaths.Count)]);
                }
                else
                {
                    this.video_playing--;
                    if (this.video_playing < 0)
                        this.video_playing = videoPaths.Count - 1;
                    FullScreenMedia.Source = new System.Uri(videoPaths[this.video_playing]);
                }
            }
        }

        private void MediaEnded(object sender, RoutedEventArgs e) 
        {
            //FullScreenMedia.Position = new TimeSpan(0);
            List<String> videoPaths = PreferenceManager.ReadVideoSettings();
            if (videoPaths.Count == 0)
            {
                ShowError("This screensaver needs to be configured before any video is displayed.");
            }
            else
            {
                if (this.shuffle)
                {
                    FullScreenMedia.Source = new System.Uri(videoPaths[new Random().Next(videoPaths.Count)]);
                }
                else
                {
                    this.video_playing++;
                    if (this.video_playing >= videoPaths.Count)
                        this.video_playing = 0;
                    FullScreenMedia.Source = new System.Uri(videoPaths[this.video_playing]);
                }
            }
        }
    }
}
